#! /usr/bin/env python
# -*- coding: utf-8 -*-

import socket
import re
import os
import time
import random
import traceback

import FileHostProtoType

def translateUnicode(str=''):
    if not str:
        return str        
    uStr= ''
    try:
        exec 'uStr=u"%s"' % str
    except:
        sys.stderr.write('%s is not a unicode string.' % str)
        return str
    return uStr

class fpitem(FileHostProtoType.HostItem):
    def __init__(self, name, type, id, link, encrypt_name='', server_name=''): 
        FileHostProtoType.HostItem.__init__(self, name, type, id, link, encrypt_name, server_name)
        
class filepost(FileHostProtoType.FileHostProcess):
    def __init__(self,user,pwd):
        FileHostProtoType.FileHostProcess.__init__(self)
        self.hostname = "filepost"
        self._opener = None
        self._user = user
        self._pwd = pwd
        self.islogin = False
        self._ftppwd = ''
        self._cookieCurl = '%s_%s.cookie' % (self._user, self.hostname)
        self._cookieCurl = os.path.join(os.path.dirname(__file__), self._cookieCurl)
        
    def login(self):
        '''
        login to filepost
        return opener object which includes cookies
        '''
        self.generateOpener()
        if self.restore_cookiejar():
            return True
        self.fherr.write('login to filepost %s/%s...'%(self._user,'*'*len(self._pwd)))
        loginData = {'email' : self._user, \
                'password' : self._pwd,
                'remember' : '1'}
        self.loginFileHost("http://filepost.com/general/login_form/", loginData)
        
        cookie_status = self.check_cookie()
        if not cookie_status:
            self.fherr.write("[%s]User %s Status : not Logined." % (time.ctime(), self._user))
            return False
        self.fherr.write('write cookie file.')
        self._cj.save(self._cookieCurl, ignore_discard=True)
        return True   
        
    def restore_cookiejar(self):
        '''
        load cookie file, then access website to verify if cookie is avaiable
        '''
        if os.path.isfile(self._cookieCurl):
            self.fherr.write('Restore Local Cookie.')
            try:
                self._cj.load(self._cookieCurl, ignore_discard=True)
            except:
                self.fherr.write('Failed to Restore Local CookieJar.')
            #access website to conferm cookie is avaiable
            return self.check_cookie()
        return False
        
    def check_cookie(self):
        indexpage = self.post_request("http://filepost.com/profile/")
        #you always see you username at the top of the page, if it logins successfully.
        if indexpage is None or self._user not in indexpage:
            self.fherr.write("[%s]User %s Status: Not Logined." % (self.hostname,self._user))
            self.islogin = False
            return False
        self.fherr.write("[%s]User %s Status: Logined." % (self.hostname, self._user))
        self.islogin = True
        return True
    
    def check_login(self):
        if self.check_cookie():
            return
        self.fherr.write('cookie unavaiable, reLogin...')
        while not self.login():
            self.fherr.write("[%s]reLogin failed." % (self.hostname, self._user))
            time.sleep(5)
    
    def getFtpPwd(self):
        '''
        get ftp password
        '''
        response = self.post_request("http://filepost.com/files/upload/ftp/")
        reFtpPwd = re.compile('Password:</label>.*?<span class="info">(?P<ftppwd>.*?)</span>', re.I|re.S)
        matchIter = reFtpPwd.finditer(response)
        for mi in matchIter:
            self._ftppwd =  mi.group('ftppwd').strip()
            return True
        return False
    
    def exportLinks(self, id=''):
        url = "http://filepost.com/files/export/"
        export_type = 'all'
        if id:
            export_type = 'selected'
        data = {'action':'export_items',
                'export_file_ids':'',
                'export_files_all':'-',
                'export_folder_ids':id,
                'export_folders_all':'-',
                'export_format':'#ID#, #URL#, #NAME#',
                'export_order':'file_name',
                'export_type':export_type}
        response = self.post_request(url, data)
        return self.parse_export_links(response)
    
    def parse_export_links(self, text):
        return []
    
    def getFileList(self):
        folders = self.getFolderList()
        files = []
        self.fherr.write("Listing files...")
        for f in folders:
            files.extend(self.getFilesFromFolder(f))
        files.sort()
        return files
    
    def getFileFromRoot(self):
        root = fpitem('Root','/root','0','')
        return self.getFilesFromFolder(root)
    
    def get_timeticket(self):
        return int(time.time()*10000)
    
    def get_SID(self):
        sessid = ''
        for cookie in self._cj:
            if cookie.name == 'SID':
                sessid = cookie.value
        return sessid
    
    def get_token(self):
        token = ''
        response = self.post_request('http://filepost.com/files/manager/').encode('utf8','ignore')
        
        reToken = re.compile("store.set\('token', '(?P<token>\w+)'\);")
        search = reToken.search(response)
        if search:
            token = search.group('token')
        return token
    
    def formatdata(self, url, data):
        params = '&'.join(['%s=%s' % (x[0],x[1]) for x in data])        
        url += '&' + params
        return url
        
    def clear_json(self, response):
        response = response.replace(r'\t','')
        response = response.replace(r'\r\n','')
        response = response.replace(r'\"','"')
        response = response.replace(r'\/','/')
        return response
        
    def getFilesFromFolder(self, folder):
        '''
        TODO: !!deal with pages!!
        '''
        files = []
        folder_id  = folder.id
        page = 1
        files_per_page = 10000
        self.fherr.write("Getting files from folder %s" % folder.name)
        url = "http://filepost.com/files/manager/?SID=%s&JsHttpRequest=%s-xml" % \
                (self.get_SID(), self.get_timeticket())
        data = [('status','active'),
                ('date_from','unundefinedefined-undefined-d'),
                ('date_to','unundefinedefined-undefined-d'),
                ('folder_id',folder_id),
                ('file_group','0'),
                ('file_type','0'),
                ('upload_type','0'),
                ('sorting_field','create_date'),
                ('sorting_type','desc'),
                ('page',page),
                ('per_page',files_per_page),
                ('search_string',''),
                ('action','search_files'),
                ]        
        url = self.formatdata(url, data)
        response = self.post_request(url)        
        response = response.replace(r'\t','')
        response = response.replace(r'\r\n','')
        response = response.replace(r'\"','"')
        response = response.replace(r'\/','/')

        reFileInfo = re.compile('show_file_dialog\((?P<file_id>\d+)\).*?>(?P<file_name>.*?)</a>.*?href="http://filepost.com/files/(?P<file_code>\w+)/')
        result = reFileInfo.finditer(response)
        for r in result:
            file_id = r.group('file_id')
            filename = translateUnicode(r.group('file_name'))
            file_code = r.group('file_code')
            file_link = 'http://filepost.com/files/%s/' % file_code
            fpI = fpitem(filename,'file',file_id,file_link)
            files.append(fpI)
        files.sort()
        return files
    
    def getFolderList(self):   
        self.fherr.write("Getting folder list(id)...") 
        foundFolders = []
        url = "http://filepost.com/files/folders_utils/?SID=%s&JsHttpRequest=%d-xml" % \
                (self.get_SID(), self.get_timeticket())         
        data = [('sorting_field','create_date'),
                ('sorting_type','desc'),
                ('action','show'),
                ('start_folder_id','0'),
                ('mode','move')]
        url = self.formatdata(url, data)
        response = self.post_request(url)
        response = self.clear_json(response)
        
        reFolder = re.compile('SelectFolder\.select\((?P<fid>\d+)\).*?>(?P<fname>.*?)</a>')
        result_iter = reFolder.finditer(response)
        for r in result_iter:
            name = translateUnicode(r.group('fname'))
            id = r.group('fid')
            item = fpitem(name, 'folder', id, 'null')
            foundFolders.append(item)
        foundFolders.sort()
        return foundFolders
    
    def find(self, filenames=[], filelist = None):
        '''
        open the filelist page according to opener with cookies
        '''
        found = []
        if filelist is None:
            filelist = self.getFileList()        
        filelistlower = [fl.name.lower() for fl in filelist]
        todel = []
        for fl in filenames:
            try:
                index = filelistlower.index(os.path.basename(fl).lower())
                found.append(filelist[index])
                todel.append(fl)
            except:
                continue
        for d in todel:
            filenames.remove(d)
        found.sort()
        return found

    def findFolder(self, foldername):        
        folders = self.getFolderList()
        for f in folders:
            if foldername == f.name:
                return f
        return None

    def createFolder(self, newfolder):
        foundfolder = self.findFolder(newfolder)
        if foundfolder is None:
            #f4s don't support subdir 
            return self.__newFolder(newfolder)
        self.fherr.write("Folder %s exsits." % newfolder)
        return foundfolder

    def __newFolder(self, newfolder, parentfolder=None):
        '''
        newfolder : without any '/',just a standard folder name
        '''
        print('Creating new folder: %s' % newfolder)
        data = [('action','edit_folder'),
                ('folder[folder_id]','undefined'),
                ('folder[name]',newfolder),
                ('folder[is_public]',1),
                ('folder[title]',''),
                ('folder[parent_id]','0')]
        url = "http://filepost.com/files/manager/?SID=%s&JsHttpRequest=%s-xml" % \
                (self.get_SID(), self.get_timeticket())
        url = self.formatdata(url, data)
        self.post_request(url)  
        return self.findFolder(newfolder)
    
    def moveto(self, items, destFolder):
        if len(items) == 0:
            return
        print('Moving...')
        data =[]
        data.append(('action', 'move_items'))
        data.append(('selected_folder', destFolder.id))
        i = 0
        for item in items:
            data.append(('items[files][%d]' % i, item.id))
            i += 1
        url = "http://filepost.com/files/manager/?SID=%s&JsHttpRequest=%s-xml" % \
                (self.get_SID(), self.get_timeticket())
        url = self.formatdata(url, data)
        self.post_request(url)  
        print('Moved.')
    
    def upload_web(self, file, progressLog=None, other_args=None):
        return self.upload_to_ftp(file, progressLog, other_args)
    
    def upload_to_ftp(self, file, progressLog=None, other_args=None):
        if not self.getFtpPwd():
            self.fherr.write('Fail to get ftp password.')
            return
        urls = ['ftp.filepost.com',
                'ftp-eu.filepost.com']
        url_num = 0
        if self.other_params.get('mirror') == 'eu':
            url_num = 1
        userpwd = ('%s:%s' % (self._user, self._ftppwd)).encode('utf8')
        target_name = self.rename_func(file)
        callback = None
        if progressLog is not None:
            callback = progressLog.write
        retry = 5
        while retry > 0:
            url = urls[url_num]
            self.fherr.write("Uploading...%s to %s" % (file, url))
            try:
                self.upload_file_to_ftp(url, userpwd, file, \
                                target=target_name.encode('utf8'), \
                                callback=callback)
            except:
                self.fherr.write(traceback.format_exc())
                self.fherr.write("Failed to upload %s to %s, try another mirror in a minute." % (file, url))
                time.sleep(60)
                retry -= 1
                url_num = (url_num+1) % 2
                continue
            break
        if retry == 0:
            self.fherr.write('max retry. failed')
            return
        
        #find newuploaded file in filemanager
        time.sleep(30)
        times = self.wait_time/60 + 1
        while times > 0:       
            self.check_login()        
            rootfiles = self.getFileFromRoot()
            find_result = self.find([target_name,], rootfiles)
            if find_result:
                new_file = find_result[0]     
                item = fpitem(os.path.basename(file), \
                              'file', \
                              new_file.id, \
                              new_file.link, \
                              target_name,\
                              new_file.server_name)
                self.newupload.append(item)
                return item
            times -= 1
            time.sleep(60)
        self.fherr.write("failed to get link for %s, try to reupload." % file)

if __name__ == "__main__":
    pass